package dao;

import java.util.ArrayList;
import java.util.List;

import javax.ejb.Stateless;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;

import model.User;
import dto.DTOUser;
import enumerations.UserType;

/**
 * Session Bean implementation class UserDao
 */
@Stateless
public class UserDao {

	@PersistenceContext
	EntityManager em;

	/**
	 * Default constructor.
	 */
	public UserDao() {
	}

	/**
	 * @author zahariem
	 * @return a User
	 * 
	 */
	public User getAdminUser() {
		User u = new User();
		try {
			u = em.createQuery("SELECT u FROM User u WHERE u.userType = ?1", User.class)
					.setParameter(1, UserType.admin)
					.getSingleResult();
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		return u;
	}

	/**
	 * @author soreas
	 * @param user
	 *            Obiectul de tip User care va fi inserat
	 * 
	 */
	public void insertUser(User pUser) {
		em.persist(pUser);
		em.flush();
	}

	/**
	 * @author soreas
	 * @param id
	 *            Idul obiectului de tip User care va fi sters
	 * 
	 */
	public void deleteUser(int pId) {
		em.remove(em.find(User.class, pId));
	}

	/**
	 * @author Zsombor
	 * @param id
	 *            Id of the user that will be returned
	 * 
	 */
	public User getUserById(int id) {
		return em.find(User.class, id);
	}

	/**
	 * @author fodorl
	 * @return List<User> returneaza o lista cu totu userii din baza de date
	 */

	public List<User> getAllUsers() {
		List<User> users = em.createQuery("SELECT u FROM User U where u.userType=?1", User.class)
				.setParameter(1, UserType.user)
				.getResultList();
		return users;
	}

	/**
	 * @author fodorl
	 * @return int returneaza id-ul unui user cu numele dat
	 */

	public int getIdUserByName(String userName) {
		int idUser = em.createQuery("SELECT u.id FROM User u where u.name=?1", Integer.class).setParameter(1, userName).getSingleResult();
		return idUser;
	}

	/**
	 * @author Zsolt
	 * @return List<String> with all usernames
	 */
	public DTOUser getAllUserNames() {
		DTOUser dtoU = new DTOUser();
		List<User> ulist = new ArrayList<User>();
		ulist = em.createQuery("SELECT u FROM User u WHERE u.userType=?1", User.class)
				.setParameter(1, UserType.user)
				.getResultList();
		for (User u : ulist) {
			dtoU.getAllUsers().add(u.getName());
		}
		return dtoU;
	}

	/**
	 * @author Zsolt
	 * @param supName
	 *            as name of the User
	 * @return a User
	 */
	public User getSupervisorByName(String supName) {
		User u = new User();
		try {
			u = em.createQuery("SELECT u FROM User u WHERE u.name=?1", User.class).setParameter(1, supName).getSingleResult();
		} catch (Exception ex) {
			ex.printStackTrace();
		}
		return u;
	}

	/**
	 * @author soreas
	 * 
	 * @param repoId
	 *            int idul repositoryului caruia vrem sa ii gasim supervisorul
	 * @return lista supervisorilor (e doar un supervisor, pt. ca nu il dorim si
	 *         pe admin in acest query)
	 */
	public List<User> listOfSupervisors(int pRepoId) {
		return em
				.createQuery("select u from User u, Membership m where m.user=u and m.user.userType=?1 and m.folder.id=?2 and m.supervisor=1",
						User.class).setParameter(1, UserType.user).setParameter(2, pRepoId).getResultList();
	}

	/**
	 * @author soreas
	 * 
	 * @param idUser
	 *            : int (idul userului)
	 * @param idRepository
	 *            : int (idul repositoryului)
	 * @return daca userul este supervisor la repository
	 */
	public boolean isSupervisor(int pIdUser, int pIdRepository) {
		List<User> listaUseri = em
				.createQuery("select u from User u, Membership m where m.user.id=?1 and m.folder.id=?2 and m.supervisor=1 and m.user.userType=?3",
						User.class).setParameter(1, pIdUser).setParameter(2, pIdRepository).setParameter(3, UserType.user).getResultList();
		if (listaUseri.size() > 0)
			return true;
		else
			return false;
	}

	/**
	 * @author soreas
	 * 
	 * @param pRepositoryId
	 *            int cu idul repositoryului in care cautam cine nu are acces
	 * @return List<User> toti userii care nu au acces la un repository
	 */

	public List<User> getUsersNotInRepository(int repositoryId) {
		List<User> usersIn = em.createQuery("select u from User u, Membership m where m.folder.id=?1 and m.user=u and u.userType=?2", User.class)
				.setParameter(1, repositoryId).setParameter(2, UserType.user).getResultList();
		List<User> usersNot = new ArrayList<User>();
		for (User user : getAllUsers()) {
			if (!usersIn.contains(user)) {
				if (!user.getName().equals("system"))
					usersNot.add(user);
			}

		}
		return usersNot;

	}
	/**
	 * @author ieneir
	 * @return
	 */

	public List<User> getAllUsersAndInvalidated() {
		List<User> users = em.createQuery("SELECT u FROM User U where u.userType=?1 or u.userType=?2", User.class)
				.setParameter(1, UserType.user)
				.setParameter(2, UserType.invalidated)
				.getResultList();
		return users;
	}
	/**
	 * @author ieneir
	 * @param searchText
	 * @return lista userilor care incep cu searchText
	 */
	public List<User> getAllUsersStartingWith(String searchText) {
		return em.createQuery("select u from User u where u.name like ?1 and u.userType!=?2 and u.userType!=?3", User.class)
				.setParameter(1, searchText + "%")
				.setParameter(2, UserType.system)
				.setParameter(3, UserType.admin)
				.getResultList();
	}

	/**
	 * @author ieneir
	 * @return toti userii cu type invalidated
	 */
	public List<User> getInvalidatedUsers() {
		List<User> users = em.createQuery("SELECT u FROM User U Where u.userType= ?1", User.class)
				.setParameter(1, UserType.invalidated)
				.getResultList();
		return users;
	}

	

	/**
	 * @author ieneir
	 * @param searchText
	 * @return userii cu type invalidated si incep cu param
	 */
	public List<User> getValidatedUsers() {
		List<User> users = em.createQuery("SELECT u FROM User U Where u.userType= ?1", User.class)
				.setParameter(1, UserType.user)
				.getResultList();
		return users;
	}

	/**
	 * @author fodorl
	 * @param idRepository
	 * @return List<User> returneaza userii care au acces la un repository si
	 *         sunt activi
	 * 
	 */

	public List<User> getValidatedUsersFromRepository(int idRepository) {
		List<User> users = em
				.createQuery("select u from User u, Membership m where m.folder.id=?1 and m.user=u and m.supervisor=0 and u.userType=?2", User.class)
				.setParameter(1, idRepository)
				.setParameter(2, UserType.user)
				.getResultList();
		return users;
	}

	/**
	 * @author ieneir
	 * @param searchText
	 * @return userii cu type user si incep cu param
	 */
	public List<User> getValidatedUsersStartingWith(String searchText) {
		return em.createQuery("select u from User u where u.userType = ?2 and u.name like ?1", User.class)
				.setParameter(1, searchText + "%")
				.setParameter(2, UserType.user)
				.getResultList();
	}

	/**
	 * @author rusho
	 * 
	 * @param id
	 *            User id
	 * @param password
	 *            New Password from SetProfile
	 */
	public void setProfilePassword(int id, String password) {

		User u = em.find(User.class, id);
		u.setPassword(password);
		em.persist(u);
	}

	/**
	 * @author soreas
	 * 
	 * @param pId
	 *            : int cu idul userului caruia ii va fi schimbat emailul
	 * @param pEmail
	 *            : adresa de email noua
	 * 
	 */
	public void setProfileEmail(int pId, String pEmail) {

		User u = em.find(User.class, pId);
		u.setEmail(pEmail);
		em.persist(u);
	}

	/**
	 * @author soreas
	 * 
	 * @param pId
	 *            : int cu idul userului caruia ii va fi schimbat emailul
	 * @param pTelephone
	 *            : telefonul nou
	 */
	public void setProfileTelephone(int pId, String pTelephone) {

		User u = em.find(User.class, pId);
		u.setTelephone(pTelephone);
		em.persist(u);
	}

	/**
	 * @author soreas
	 * 
	 * @param pUserName
	 *            String cu numele cautat
	 * @return Lista de useri
	 */
	public List<User> getUsersByName(String pUserName) {
		return em.createQuery("Select u from User u where u.name = ?1", User.class).setParameter(1, pUserName).getResultList();
	}

	/**
	 * @author ieneir
	 * @param uId
	 */
	public void invalidateUser(Integer uId) {
		User user = (User) em.find(User.class, uId);
		user.setUserType(UserType.invalidated);
		em.merge(user);

	}

	/**
	 * @author ieneir
	 */
	public void validateUser(Integer id){
		User user = (User) em.find(User.class, id);
		user.setUserType(UserType.user);
		em.merge(user);
	}

	/**
	 * @author ieneir
	 * @param enteredName
	 * @return
	 */

	public boolean existsNameInDB(String enteredName) {
		List<User> usr = (List<User>) em
				.createQuery("SELECT u FROM User u WHERE u.name= :par",
						User.class).setParameter("par", enteredName)
						.getResultList();
		return usr.size() > 0;
	}

	/**
	 * @author ieneir
	 * @param enteredEmail
	 * @return
	 */
	public boolean existsEmailInDB(String enteredEmail) {
		List<User> usr = (List<User>) em
				.createQuery("SELECT u FROM User u WHERE u.email= :par",
						User.class).setParameter("par", enteredEmail)
						.getResultList();
		return usr.size() > 0;

	}
	
	/**
	 * @author fodorl
	 * @param String 
	 * @return User entity
	 * returneaza un user entity cu numele introdus
	 */
	
	public User getUserByName(String userName){
		return em.createQuery("Select u from User u where u.name=?1", User.class).setParameter(1, userName).getSingleResult();
	}
	
	/**
	 * @author rusho
	 * @param id
	 * @return 
	 */
	public String getEmailbyId(Integer id) {
		User u = em.find(User.class, id);
		return u.getEmail();
		
	}
	
	/**
	 * @author rusho
	 * 
	 * @param id
	 * @param enteredPhone
	 */
	
	public void setProfilePhone(Integer id, String enteredPhone) {
		User u = em.find(User.class, id);
		u.setTelephone(enteredPhone);
		em.persist(u);
		
	}

	/**
	 * @author rusho
	 * 
	 * @param id
	 * @return
	 */
	
	public String getPhoneByID(Integer id) {
		User u = em.find(User.class, id);
		return u.getTelephone();
	}
}
